package router

import (
	"fmt"
	"gitee.com/cdsailyj/go-vpn/app/index/api"
	"gitee.com/cdsailyj/go-vpn/app/index/middleware"
	"gitee.com/cdsailyj/go-vpn/common/tool"
	"gitee.com/cdsailyj/go-vpn/common/util/vpn"
	"github.com/gin-gonic/gin"
	"io"
	"net/http"
	"os"
	"runtime/debug"
	"strings"
)

func SetupRouter() *gin.Engine {
	//修改日志位置
	//gin.ForceConsoleColor() //使用颜色打印
	//gin.DebugPrintRouteFunc() 修改日志打印格式
	gin.DisableConsoleColor() //禁用颜色打印

	appPath := tool.GetAppPath()
	f, _ := tool.OpeFile(appPath+"log/go-vpn.log", 0777)
	//defer f.Close()
	//gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

	r := gin.New()
	// 自定义 panic 错误处理
	r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
		// 打印调用堆栈
		//debug.PrintStack()
		stackArr := strings.Split(string(debug.Stack()), "\n") //堆栈信息数组
		err, _ := recovered.(string)
		c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"msg": "系统错误," + fmt.Sprint(err), "code": 100, "stack": stackArr})
	}))

	// 自定义日志中间件
	r.Use(func(c *gin.Context) {
		// 只有非静态资源请求才记录日志
		fmt.Sprintf("surl: %#v \n", c.Request)
		if tool.ShouldLog(c.Request.URL.Path) {
			gin.LoggerWithWriter(io.MultiWriter(f, os.Stdout))(c)
		}
		c.Next()
	})

	r.Use(middleware.Request)

	// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
	r.MaxMultipartMemory = 100 << 20 // 100 MiB

	indexController := api.Index{}
	index := r.Group("index")
	index.GET("welcome", indexController.Welcome)

	/*websocket相关*/
	wsController := api.Ws{}

	r.GET("/control-get", wsController.ControlGet)
	r.GET("/control-put", wsController.ControlPut)
	r.GET("/control-self", wsController.ControlSelf)
	r.GET("/frame-get", wsController.FrameGet)
	r.GET("/frame-put", wsController.FramePut)

	// webrtc 信令服务器
	server := vpn.NewSignalingServer()
	r.GET("/ws", server.HandleWebSocket)
	r.GET("/webrtc/users", server.Users)

	// http接口
	apiVpn := api.Vpn{}
	vpnGroup := r.Group("vpn")

	vpnGroup.GET("list", apiVpn.List)
	vpnGroup.POST("stop-vpn", apiVpn.StopVPN)
	vpnGroup.POST("start-vpn", apiVpn.StartVPN)
	vpnGroup.POST("sync", apiVpn.Sync)

	SettingApi := api.Setting{}
	r.Group("setting").Any("list", SettingApi.List).POST("edit", SettingApi.Edit)

	// 如果只是路由到前端目录，不打包到exe
	//r.StaticFS("/dist", http.Dir(appPath+"dist"))
	//r.Static("/dist", appPath+"dist")
	//404的时候进入方法
	r.NoRoute(func(c *gin.Context) {
		// 如果有对应路径的文件在dist目录找到，则返回文件
		file := appPath + "dist" + c.Request.URL.Path
		if _, err := os.Stat(file); err == nil {
			c.File(file)
			return
		}
		//否则返回index内容
		c.File(appPath + "dist/index.html")
	})

	// --end  如果只是路由到前端目录，不打包到exe

	// 如果需要将前端代码打包到最终的exe可执行程序
	/*
		// 如果要重定向子路径的URL
		//sub, _ := fs.Sub(vue.Dist, "dist/assets")
		//r.StaticFS("/assets", http.FS(sub))

		// 将所有请求都重定向到 index.html，但只有在文件不存在时
		distFS := http.FS(vue.Dist)
		r.NoRoute(func(c *gin.Context) {
			path := "dist" + c.Request.URL.Path //指向 dist 目录的文件
			// 检查文件是否存在
			_, err := vue.Dist.Open(path)
			if err != nil {
				// 文件不存在，直接返回 index.html 的内容
				indexContent, _ := fs.ReadFile(vue.Dist, "dist/index.html")
				c.Data(http.StatusOK, "text/html; charset=utf-8", indexContent)
				return
			}

			c.FileFromFS(path, distFS) //读取对应文件
			//http.FileServer(distFS).ServeHTTP(c.Writer, c.Request) //另一种方式读取对应文件
		})
	*/

	//----end 如果需要将前端代码打包到最终的exe可执行程序

	return r
}
